Java拆箱和装箱
使用包装器类和装箱
包装器类的主要用途
为基本类型提供分类功能,这些功能中的大多数与各种转换相关:如在基本类型之间与String对象进行转换。
创建包装器对象
除了Character之外,所有的包装器都提供两个构造函数
一个是基本类型,另一个就是字符串,如:
1 2 3 4
| Integer i1 = new Integer(10); Integer i2 = new Integer("10"); Character类只提供一种构造函数 Character c1 = new Character('a');
|
Boolean包装器的构造函数可以是带有bollean值true或false,或者一个不区分大小写”true”或是“false”但是需要注意的一点是如下代码:
1 2 3 4
| Bollean flag = new Bollean("true"); if(flag) { }
|
编译器自动把Boolean“取消装箱” 成一个boolean.
valueOf()方法
它是由包装类的静态方法
它还有一个可以带额外参数(int radix)的重载方法,返回一个包装器类
1
| Integer i2= Integer.valueOf("101011",2);
|
第二个参数表示进制, 首先将101011转换成43 然后将43赋值给id对象
xxxValue()方法
用于把包装的值转换为一个基本类型的数据
1 2 3
| Integer i2 = new Integer(55); byte b = i2.byteValue(); double d = i2.doubleValue();
|
pareseXXX()方法
parseXXX()与valueOf()都是以String作参数,如果String形式不对,则抛出NumberFormatException
它也是包装器的一个静态方法,但其返回的是一个基本类型的数据。
1 2
| double d = Double.parseDouble("1.23"): parseXXX()也可以像valueOf()一样传一个基数参数
|
自动装箱
1 2 3 4 5 6 7 8 9
| Integer y = new Integer(567); y++; System.out.println("y = " + y); Integer y = new Integer(567); int x = y.intValue(); x++; y = new Integer(x); System.out.println("y = " + i);
|
1 2 3 4 5 6 7 8 9 10
| Integer y = 567; Integer x = y; System.out.println(y==x); y++; System.out.println(x + " " + y); System.out.println(y==x); 输出结果 true 567 568 false
|
y++相当于以下操作
1 2 3
| int x2= y.intValue(); x2++; y = new Integer(x2);
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Integer i3 = 10; Integer i4 = 10; if(i3 == i4) { System.out.println("same object"); } if(i3.equals(i4)) { System.out.println("meaningfully equal"); } 输出结果: same object meaningfully equal
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Integer i1 = 500; Integer i2 = 500; if(il != i2) { System.out.println("different objects"); } if(i1.equals(i2)) { System.out.println("meaningfully equal"); } 输出结果: different objects meaningfully equal
|
为什么i3和i4是相同的对象,然而i1和i2是不同的对象呢
1
| In order to save memory, two instances of the following wrapper objects will always be = = when their primitive values are the same:
|
-128–127之间的值,它们被装箱为Integer对象后,会在内存中被重用,超过这个值的时候每次装箱是会产生新的对象
box&unbox给重载带来的问题
1 2 3 4 5 6 7 8
| class Test{ static void go(Integer x) { System.out.println("Integer"); } static void go(long x) { System.out.println("long"); } public static void main(String [] args) { int i = 5; go(i); } }
|
编译器选择的是加宽操作而不是装箱
1 2 3 4 5 6 7 8
| class Test{ static void go(int x, int y) { System.out.println("int,int");} static void go(byte... x) { System.out.println("byte ... "); } public static void main(String[] args) { byte b = 5; go(b,b); } }
|
加宽会优先于var-arg执行
加宽优于装箱
加宽优于var-arg
那装箱与var-arg的关系如何???
1 2 3 4 5 6 7 8 9
| class Test{ static void go(Byte x, Byte y) { System.out.println("Byte, Byte"); } static void go(byte... x) { System.out.println("byte... "); } public static void main(String [] args) { byte b = 5; go(b,b); } }
|
装箱会优于var-arg操作
加宽>装箱>var-arg
Attention
1 2 3 4 5 6 7
| class Test{ public static void main(String [] args) { Test d = new Test(); d.test(new Integer(5)); } void test(Long x) { } }
|
编译错误
加宽对于对象来说是依赖于继承的
从一个包装器类加宽到另一个包装器类是非法的,因为包装器之间的平等的,不符合IS-a原则
Short IS-A Integer 这种说法是错误的
总结
- 基本加宽使用可能“最小的”方法参数
- 不能先加宽,后装箱(int 不能转成Long)
- 可以先装箱,后加宽(int可以通过Integer变成object,Integer继承object)